Fix issue 14795: ComboBox with DropDownStyle.Simple renders incorrectly and displays an unexpected vertical scrollbar - #14827
Conversation
…ly and displays an unexpected vertical scrollbar
There was a problem hiding this comment.
Pull request overview
This PR addresses WinForms issue #14795 by correcting the Net11 modern-visual-styles rendering/layout of ComboBoxStyle.Simple, eliminating the visual interference that produced an unexpected vertical scrollbar strip and improving edit/list geometry consistency.
Changes:
- Adjusts modern Simple-mode layout to stabilize edit/list sizing, remove list borders, and clip the list bottom to preserve the rounded outer frame.
- Adds an accent-colored divider between the edit area and the list area during modern painting.
- Adds regression tests covering Simple-mode edit/list bounds, divider rendering, list border removal, and CreateParams flags.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/test/unit/System.Windows.Forms/System/Windows/Forms/ComboBoxTests.cs | Adds regression tests for modern Net11 + Simple layout, divider rendering, and style flags. |
| src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.ModernComboAdapter.cs | Draws an accent divider between the Simple edit and list areas during modern rendering. |
| src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.Modern.cs | Reworks modern Simple-mode geometry; removes list borders; applies a clip region to avoid rounding artifacts. |
| src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.cs | Tweaks CreateParams (integral height for modern Simple) and applies list border adjustments on handle creation; modernizes NCCALCSIZE/NCHITTEST behavior for Simple. |
Comments suppressed due to low confidence (2)
src/test/unit/System.Windows.Forms/System/Windows/Forms/ComboBoxTests.cs:1315
- These assertions only check one-sided bounds (<= / >=), which can let significant misalignment slip through. Using InRange with a small tolerance makes the test better at catching regressions while still allowing minor off-by-one differences.
Assert.True(listBounds.Left <= control.ModernChromeInsets.Left);
Assert.True(listBounds.Right >= control.ClientRectangle.Right - control.ModernChromeInsets.Right - 1);
src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.Modern.cs:610
- The value "2" is a magic number used to crop the visible list area. Giving it a named constant (even a local const) makes it clearer what the crop represents and helps keep related calculations consistent if it needs adjustment later.
int bottomShrink = ScaleHelper.ScaleToDpi(2, DeviceDpiInternal);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (!_integralHeight | ||
| || (UsesModernComboAdapter | ||
| && DropDownStyle == ComboBoxStyle.Simple | ||
| && !_integralHeightExplicitlySet)) |
There was a problem hiding this comment.
This “explicitly set” state is not preserved by WinForms designer serialization. IntegralHeight still has [DefaultValue(true)], so the designer omits an assignment when its value is true; after reopening the form, _integralHeightExplicitlySet is therefore false and CBS_NOINTEGRALHEIGHT is silently enabled. Two controls with the same serialized/public value can behave differently based only on setter history. This needs value-based, serializable semantics (or custom reset/serialization handling), rather than an unpersisted flag.
| int bottomShrink = ScaleHelper.ScaleToDpi( | ||
| ModernSimpleBottomCropLogicalPixels, | ||
| DeviceDpiInternal); | ||
| int visibleHeight = Math.Max(1, targetBounds.Height - bottomShrink); |
There was a problem hiding this comment.
The bottom crop is still applied twice. ComputeModernComboTargetState already subtracts ModernSimpleBottomCropLogicalPixels (and the divider thickness) when calculating simpleListBottom, then this region removes the same crop again. At 96 DPI the intended ~2px crop becomes roughly 5px (2 + divider + 2), potentially clipping the last row or the bottom of the scrollbar. Please apply the crop in only one place.
Fixes #14795
Root Cause
When
VisualStylesModeis set toNet11,ComboBoxStyle.Simpleretains certain "classic/native" geometric and non-client area behaviors, resulting in inconsistencies when overlaid with modern rendering:Proposed changes
Customer Impact
Regression?
Risk
Screenshots
Before
After
Normal
DarkMode
Test methodology
Test environment(s)
Microsoft Reviewers: Open in CodeFlow